package com.inspur.edp.udt.designtime.api.utils;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import com.inspur.edp.cef.designtime.api.element.GspEnumValue;
import com.inspur.edp.cef.designtime.api.entity.MappingInfo;
import com.inspur.edp.cef.designtime.api.entity.MappingRelation;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnInfo;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import com.inspur.edp.udt.designtime.api.entity.element.UdtElement;
import com.inspur.edp.udt.designtime.api.exception.UdtModelErrorCodeEnum;
import com.inspur.edp.udt.designtime.api.exception.UdtModelException;

import java.util.UUID;
import java.util.stream.StreamSupport;

public class UpdateElementUtil {

  /**
   * 根据引用的udt元数据更新字段
   */
  public final void updateElementWithRefUdt(UdtElement element, UnifiedDataTypeDef udt) {
    element.setUdtID(udt.getId());
    element.setUdtName(udt.getName());

    Object tempVar = element.getMappingRelation().clone();

    MappingRelation mappingInfos = (MappingRelation) ((tempVar instanceof MappingRelation) ? tempVar
        : null);

    GspFieldCollection childElements = element.getChildElements().clone(null, null);

    element.getMappingRelation().clear();
    element.getChildElements().clear();

    if (udt.getColumns().size() > 0) {

      for (ColumnInfo col : udt.getColumns()) {

        String columnInfoId = col.getID();
        MappingInfo mappingInfo;
        UdtElement childElement;
        if (mappingInfos != null && mappingInfos.getValues().contains(columnInfoId)) {
          // ① childElement已存在，更新；
          mappingInfo = StreamSupport.stream(mappingInfos.spliterator(), false)
              .filter((item) -> item.getValueInfo().equals(columnInfoId)).findFirst().orElse(null);

          String childElementId = mappingInfo.getKeyInfo();
          Object tempVar2 = childElements.stream()
              .filter((item) -> item.getID().equals(childElementId)).findFirst().orElse(null);

          childElement = (UdtElement) ((tempVar2 instanceof UdtElement) ? tempVar2 : null);
          if (childElement == null) {
            throw UdtModelException.createException(UdtModelErrorCodeEnum.GSP_BEMODEL_UDT_MODEL_0003, childElementId);
          }
        } else {
          // ② 新增
          childElement = GetChildElement();
          MappingInfo tempVar3 = new MappingInfo();
          tempVar3.setKeyInfo(childElement.getID());
          tempVar3.setValueInfo(columnInfoId);
          mappingInfo = tempVar3;
        }
        // 根据columnInfo更新childElement
        mapColumnInfoToField(col, element.getLabelID(), childElement);

        element.getMappingRelation().add(mappingInfo);
        element.getChildElements().add(childElement);
      }
    }

    // 其他属性
    if (udt instanceof ComplexDataTypeDef) {
      updateComplexDataTypeDefProperties(element, (ComplexDataTypeDef) udt);
    } else if (udt instanceof SimpleDataTypeDef) {
      updateSimpleDataTypeDefProperties(element, (SimpleDataTypeDef) udt);
    }
  }

  /**
   * 转换columnInfo为childElement
   *
   * @param ele 映射字段
   */
  public final void mapColumnInfoToField(ColumnInfo info, String prefix, UdtElement ele) {
    if (UdtUtils.checkNull(prefix)) {
      throw UdtModelException.createException(UdtModelErrorCodeEnum.GSP_BEMODEL_UDT_MODEL_0004);
    }
    String newLabelId = prefix + "_" + info.getCode();
    ele.setLabelID(newLabelId);
    ele.setCode(newLabelId);
    ele.setName(info.getName());
    ele.setMDataType(info.getMDataType());
    ele.setDefaultValue(info.getDefaultValue());
    ele.setLength(info.getLength());
    ele.setPrecision(info.getPrecision());
  }

  /**
   * 根据多值udt更新字段的其他属性
   */
  private void updateComplexDataTypeDefProperties(UdtElement element, ComplexDataTypeDef cUdt) {
    if (UdtUtils.checkNull(element.getCode())) {
      element.setCode(cUdt.getCode());
    }
    if (UdtUtils.checkNull(element.getName())) {
      element.setName(cUdt.getName());
    }

    UdtElement newElement;
    if (cUdt.getElements().size() == 1
        && cUdt.getDbInfo().getMappingType() != ColumnMapType.SingleColumn) {
      newElement = (UdtElement) cUdt.getElements().get(0);
//      newElement = (UdtElement)((tempVar instanceof UdtElement) ? tempVar : null);
    } else {
      newElement = new UdtElement(cUdt.getPropertys());
    }

    element.setObjectType(newElement.getObjectType());
    // 若为[单一列]的映射关系，可能导致超长，需把数据类型改为[Text]
    if (cUdt.getDbInfo().getMappingType() == ColumnMapType.SingleColumn) {
      element.setMDataType(GspElementDataType.Text);
      element.setLength(0);
      element.setPrecision(0);
    } else {
      element.setMDataType(newElement.getMDataType());
      element.setLength(newElement.getLength());
      element.setPrecision(newElement.getPrecision());
    }
    element.setDefaultValue(newElement.getDefaultValue());
    element.getChildAssociations().clear();
    element.getContainEnumValues().clear();
  }

  /**
   * 根据单值udt更新字段的其他属性
   */
  private void updateSimpleDataTypeDefProperties(UdtElement element, SimpleDataTypeDef sUdt) {
    if (UdtUtils.checkNull(element.getCode())) {
      element.setCode(sUdt.getCode());
    }
    if (UdtUtils.checkNull(element.getName())) {
      element.setName(sUdt.getName());
    }
    if (isConstraint(sUdt, "DataType")) {
      element.setMDataType(sUdt.getMDataType());
    }
    if (isConstraint(sUdt, "Length")) {
      element.setLength(sUdt.getLength());
    }
    if (isConstraint(sUdt, "Precision")) {
      element.setPrecision(sUdt.getPrecision());
    }
    if (isConstraint(sUdt, "ObjectType")) {
      element.setObjectType(sUdt.getObjectType());

      // 关联
      element.getChildAssociations().clear();
      if (sUdt.getChildAssociations() != null && sUdt.getChildAssociations().size() > 0) {
        for (GspAssociation item : sUdt.getChildAssociations()) {
          element.getChildAssociations().add(convertUdtAssociation(item, element));
        }
      }

      element.setEnumIndexType(sUdt.getEnumIndexType());
      // 枚举
      element.getContainEnumValues().clear();
      if (sUdt.getContainEnumValues() != null && sUdt.getContainEnumValues().size() > 0) {
        for (GspEnumValue item : sUdt.getContainEnumValues()) {
          element.getContainEnumValues().add(item);
        }
      }
    }
    if (isConstraint(sUdt, "DefaultValue")) {
      element.setDefaultValue(
          sUdt.getDefaultValue() == null ? null : sUdt.getDefaultValue().toString());
    }
    if (isConstraint(sUdt, "IsRequired")) {
      element.setIsRequire(sUdt.getIsRequired());
    }

    //// UnifiedDataType属性，前端根据[约束]/[模板]控制属性是否可编辑
    //element.UnifiedDataType = sUdt;
  }

  /**
   * 是否约束
   */
  private boolean isConstraint(SimpleDataTypeDef sUdt, String propertyName) {
    // todo: 需要区分新增udt引用与刷新
    return true;

    //if (sUdt.PropertyUseTypeInfos.ContainsKey(propertyName))
    //{
    //	var type = sUdt.PropertyUseTypeInfos[propertyName];
    //	return type.PropertyUseType == UseType.AsConstraint;
    //}
    //else
    //{
    //	throw new System.Exception($"单值业务字段的约束信息中无属性名[{propertyName}]");
    //}
  }

  private GspAssociation convertUdtAssociation(GspAssociation asso, UdtElement ele) {
    Object tempVar = asso.clone();

    GspAssociation udtAsso = (GspAssociation) ((tempVar instanceof GspAssociation) ? tempVar
        : null);
    if (udtAsso != null && udtAsso.getRefElementCollection().size() > 0) {

      GspFieldCollection refElementCollection = udtAsso.getRefElementCollection()
          .clone(udtAsso.getRefElementCollection().getParentObject(), udtAsso);
      udtAsso.getRefElementCollection().clear();
      for (IGspCommonField refEle : refElementCollection) {
        udtAsso.getRefElementCollection().add(
            convertUdtRefElement((UdtElement) ((refEle instanceof UdtElement) ? refEle : null),
                ele.getLabelID()));
      }
    }
    return udtAsso;
  }

  private UdtElement convertUdtRefElement(UdtElement udtEle, String prefix) {
    Object tempVar = udtEle.clone();

    UdtElement newEle = (UdtElement) ((tempVar instanceof UdtElement) ? tempVar : null);

    String newLabelId = "";
    if(newEle != null){
      newLabelId = prefix + "_" + newEle.getLabelID();
      newEle.setLabelID(newLabelId);
    }
    return newEle;
  }

  /**
   * 创建字段实例
   */
  protected final UdtElement GetChildElement() {
    return new UdtElement(new ComplexDataTypeDef().getPropertys()) {
      {
        setID(UUID.randomUUID().toString());
      }
    };
  }
}
